import ChainOfResponsinility.*;
import factory.*;
import observer.*;
import singleton.demo1.*;
import singleton.demo1.strategy.Sort;
import singleton.demo1.strategy.Test01;
import singleton.demo1.strategy.TestSort01;
import singleton.demo1.strategy.TestStrategy01;
import singleton.demo1.strategy.learn.*;

import java.beans.PropertyEditorManager;
import java.util.Comparator;
import java.util.Properties;
import java.util.concurrent.ExecutionException;

/**
 * c++设计模式GOF
 *
 *
 * 直播 obstudio 客户端 nginx rtmp
 *
 * idea 社区版本
 * 马士兵23种设计模式
 * book effective java
 *
 * @description
 * 1、单例设计模式 singleton
 * 只需要存在一次实例化的比如工厂。
 * Test01 线程安全也是比较常用的 饥汉模式
 * Class.forName("classname") 把class load到内存 静态变量只要它的宿主类load到内存就会初始化变量。
 * Test03 饱汉模式 线程不安全
 * lambda 表达式对只有一个方法的匿名内部类初始化。 Thread 接受一个 Runnable 只有一个方法 可以用匿名类直接初始化 也可以用lambda表达式
 * Test04 在 Test03的基础上加锁 语句重排 JIT  如果共享资源不加volatile会产生问题 在没有初始化的时候就返回 instance
 * Test05 内部类实现 单例 线程安全 volatile 为什么要加这个？ 牵扯到java 虚拟机执行 java 汇编语言会有个指令集优化 如果用到了jit的优化必须需要加上volatile修饰 没有使用jit可以不加
 * Test06 enum 实现单例 反序列化不成枚举 完美中的完美  上面所有的内容都可以用class.forName load进来在实例化 反射 这个可以挡住反射。枚举单例不会被反序列化原因 枚举类没有构造方法。 反编译后是abstruct class spring bean 工厂可以完成单例
 *
 * 2、策略模式
 * jdk 1.8 之后 接口可以有默认方法实现 为了支持lambda
 * Comparator compare a b 比较
 * Comparable compareTo 和另一个比较
 * 范型是编译时候检查运行起来就不检查了。
 * 什么是开闭原则 我自己理解 类定义好了尽量不动 如果要增强尽量是添加和少部分修改。
 * @FunctionalInterface // 这个加不加都行
 * public interface FunctionInterface {
 *     // 定义函数类型
 *     int Say(int a, int b);
 *     default void m(){System.out.println("test");} 1.8之后可以实现方法这个是给lamda用的
 * }
 *配置文件
 *
 * 3、工厂设计模式
 * IOC 控制反转 依赖注入 provider customer
 * 抽象工厂
 * 名词用抽象类 形容 词用接口。 抽象类和接口在于语义的区分 不知道的用接口。
 *
 * 简单工厂（工厂方法） 在单一的产品上的纬度好扩展
 * 抽象工厂 在产品一族好扩展 但是在单一产品比较不好扩展
 *
 * 更好的解决方案是spring 带来的bean工厂
 *
 * spring maven（构建管理 解决依赖等等 不同版本的问题等等管理）  -> 右键项目增加maven的支持
 * maven
 *   groupid 所在单位的名称
 *   axxxd   产品的名字
 *   version 版本
 *
 * spring 如何引入？ https://mvnrepository.com/
 * 搜索 spring context
 * 找到maven的粘贴过来
 * 加一个 <dependencies>贴到这里</dependencies>
 *
 * 4、调停者模式 中介者  多个对象彼此都有调用关系 需要一个中间人来处理 mq kfk  对内  比如坦克的 火炮 轮子 零件他们彼此的调用就是内部
 *
 * 5、Facade模式 对外 画板  和  坦克的零件 就是对外 比如画板检测碰撞检测坦克零件的碰撞检测
 *
 * TankFrame
 *
 * 第一步先搞一个门面 把零件的碰撞都抽离出来、再就是添加新的物体
 * Frame     显示
 * Gamemodel 做模型的计算
 *
 * 添加新的物体 GameObject 父类
 *
 * 6、装饰器 在原有的对象基础上加上修饰，比如坦克加上血槽 穿越等等总之就是修饰原来对象 用来扩展对象，增强功能
 * Tank
 * TankDecorator  ->  修饰坦克
 *   tank -> 聚合tank 如果需要把装饰加到任意的对象这里聚合tank的实例显然不合适。 这里比较合适的是聚合gameobject
 *   print() -> tank.print(); 调用装饰器的同时调用tank的print
 *
 * TankDecorator
 *   GameObject gameObject
 *   print() -> gameObject.print()
 *
 * 7、责任链
 *   Chain of Responsibility
 *
 * 8、reator Reactor 反应堆设计模式 https://www.jianshu.com/p/458e4b276607 待学习
 *
 * 9、观察者 Observer 发布订阅
 *
 * 10、组合composite [树状模式专用结构]
 *
 * 11、享元设计模式 fly weigth 重复利用对象 线程池 链接池  对象创建后用完放到池子里 在用在拿防止重复new 如果池子没有在new 共享元数据
 *     java String 用的就是享元模式 java 中所有的字符串都在常量池里面
 *     s1 = "abc"
 *     s2 = "abc" s1 s2 都是指向一个常量池。 如果没有在常量池创建 如果有 直接让s2的指向s1  new String("abc")
 *     这是返回的地址但是地址指向的也是"abc" 这个常量池的内容。
 *     s3 = new String("abc")
 *     s3.intern() == s1 这个是true intern 指的是 s3堆对应常量池的那个引用内容。 总是优先去常量池拿。 s1 s2 的引用是一样的  s3 intern
 *     后引用和 s1是一样的都是常量池中的地址。 共享常量池的地址 这就是享元模式。
 *
 * 12、代理模式 proxy
 * 静态代理
 * 动态代理
 * aop 切面  封装通用业务逻辑的组件，即我们想要插入的代码内容 切入点：指定哪些Bean组件的哪些方法使用切面组件 用于指定具体作用的位置，是方法之前或之后等等  慎用继承【耦合度太高 】
 *
 * 13、迭代器Iterator 用在做遍历的。
 *
 * 14、visitor 访问者设计模式 在结构不变的情况下，动态改变对于内部元素的动作。
 *
 * 15、asm c语言 __asm__{} 可以直接写汇编  java的直接操作字节码 java的汇编语言 .class文件 https://www.cnblogs.com/yaoyinglong/p/4297793.html
 * java 虚拟机规范 阿里 Dragonwell 可以去 oracle官方找
 * https://docs.oracle.com/en/java/javase/15/
 * https://docs.oracle.com/javase/specs/index.html -》 The Java Virtual Machine Specification, Java SE 15 Edition 看class 第四章节
 * 选进到类体 菜单 view show bytecode 相当于javap 观察类的初始化 需要java的汇编支持 要搞懂他们的意思  插件jclasslib -> view ->  show jclass xxx
 * asm 是对二进制code的一个操作 new ClassReader("")  读取类结构 配合 visitor使用 ClassWrite(0) cw.visitxxx 动态生成字节码   往回写 asm 官方下pdf
 * http://asm.ow2.io/ https://asm.ow2.io/asm4-guide.pdf
 *
 * asm生成动态代理什么原理。
 * 1、cr = ClassReader("tank.class") 加到内存
 * 2、cw = 创建ClassWriter(0)
 * 3、定义classVisitor
 * 4、cr.accept(cw, 0)
 * 5、byte[] b2 = cw.toByteArray();
 * 到这里相当于把 tank复制了一份
 *
 * 6、往下看asm截图  图中 cr.accept(cw如果换成 cv   cv visitor 在副本上修改内容并且保存 这个时候就可以随意加上代码作为动态代理
 *
 * 16、builder 构建复杂对象 分离复杂对象的构建和表示 对象特别多的时候可以按照部分构建 Effect java
 *
 * 17、Adapter/Wrapper 适配器模式 接口转换 或者叫包装器。 类似 jdbc odbc 客户端api一样 但是接入的适配器不同 他们下面可以接不同db
 * jdbc 通过适配器 odbc 去访问sql server Java 是直接访问的 jdbc jdbc 通过适配器去访问 sql server
 * java 里面的adapter类并不是真的adapter模式 WindowAdapter keyAdapter 这俩啥模式都不是只是一种比较方便的编程方式。
 *
 * 18、Bridge 桥接模式 双纬度的
 * 比如讲礼物gift抽象类
 * 下面又可以分 狂野礼物 冷酷礼物
 * 下面还可以再分其他的 抽象物种
 * 如果实现去继承他们就每一种抽象都需要去实现无法继承
 *        gift
 *    冷酷     温软    xxx   xxx ... (纬度一 抽象的方向)      m
 *    book    book   xxx   xxx ... （纬度二 实现类也在发展）  n
 *    （多个纬度同时在发展、抽象的礼物在发展  实现抽象的类也在发展） m*n 的增长
 *
 *  实现的树、抽象的树分离开发展 用聚合代替继承
 *
 *  18、command 命令模式
 *
 *  19、原型链子模式 内部支持 Object.clone() 所以原型也叫克隆
 *  实现原型模式需要实现克隆接口 cloneable（标记型接口，不需要实现任何方法）
 *  需要注意深克隆和浅克隆
 *
 *  20、Memento 备忘录模式 记录状态便于回归
 *
 *  21、TemplateMethod 模版方法 钩子函数
 *
 *  22、state状态模式 根据状态决定行为。 有限状态机器 FSM 状态迁移需要根据当前状态决定。
 *
 *  23、intepreter 动态脚本解析 解释器 解析脚本语言的类似正则表达式。 相当于写了一个解释器
 *
 *  总结
 *    创建型模式
 *
 *    结构型模式
 *
 *    行为型模式
 *
 *
 *  面向对象六大设计原则
 *  1、可维护性
 *    修改的时候改的越少越好。
 *  2、可复用性
 *    代码可以被以后重复使用。
 *  3、可扩展性
 *    添加代码无需修改原来代码。
 *  4、灵活性
 *    代码接口可以灵活调用。
 *
 *  设计原则
 *  1、单一职责 一个类不要设计的太大要完成某一个单一的任务。 比如Persion 不要涉及到 persionMange Persion 的管理 做到高內聚低耦合。
 *  2、开闭原则 对扩展开放 对修改关闭。抽象多态是开闭原则的重要关键
 *  3、里氏替换原则 所有使用父类的地方都可以透明使用子类
 *  F fa = new F(); //能用父的
 *  可以用
 *  F fa = new Child(); // 子也可用 子类可以完全替代父类就行。
 *  4、依赖倒置 这个spring的di不同这不是依赖注入。这里是面向接口编程。
 *  5、接口隔离原则 例如 fly runing 两个接口不应该搞一个 既可以飞有可以跑的接口这个和go还是有区别的。 go 是面向行为
 *  这里是有语意的。 客户用不到的方法不要往外暴露，只暴露最小的接口。
 *  6、迪米特法则 只和自己熟悉的对象打交到
 *  1、this
 *  2、参数传入的
 *  3、成员对象
 *  4、内部维护的对象集合
 *  5、当前对象创建的对象
 *
 *
 *  bio nio aio https://www.jb51.net/article/192321.htm
 */
public class main {
    public static void main(String[] args){
        // singleton demo01
        /*Test01 test01 = Test01.getInstance();
        test01.say();
        Test01 test011 = Test01.getInstance();
        System.out.println(test011 == test01);*/
        /*TestLearn01 testLearn01 = TestLearn01.getInstance();
        testLearn01.say();
        TestLearn01 testLearn011 = TestLearn01.getInstance();
        System.out.println(testLearn011 == testLearn01);*/

        // singleton demo02 静态代码块初始化本质和第一个没区别
        /*Test02 test02 = Test02.getInstance();
        test02.say();*/

        // singleton lazy load 饱汉模式 线程不安全
        /*for(int i=0;i<100;i++){
            new Thread(()->{
                System.out.println(Test03.getInstance());
            }).start();
        }*/
        /*for(int i = 0; i < 100;i++){
            new Thread(()->{
                System.out.println(TestLearn03.getInstance());
            }).start();
        }*/

        // singleton Test04 饱汉模式 加锁线程安全 但是效率不行
        /*for(int i = 0;i<100;i++){
            new Thread(()->{
                System.out.println(Test04.getInstance());
            }).start();
        }*/

        // 内部类实现单例
        /*for(int i=0;i<100;i++){
            new Thread(()->{
                System.out.println(Test05.getInstance());
            }).start();
        }*/

        // singleton enum 单例
        /*for(int i=0;i<100;i++){
            new Thread(()->{
                System.out.println(Test06.INS.hashCode());
                Test06.INS.say();
            }).start();
        }*/

        // 策略模式
        /*int [] a = {12,1,4,4,5};
        Sort sort = new Sort();
        sort.sort(a);
        for(int i:a){
            System.out.println(i);
        }*/

        /*Test01 [] test01s = {
                new Test01(22),
                new Test01(122),
                new Test01(2),
                new Test01(2222),
        };


        TestSort01 testSort01 = new TestSort01();
        testSort01.sort(test01s);

        for(Test01 item:test01s){
            System.out.println(item.width);
        }*/

        // 策略模式 Comparator
        // 创建需要排序的对象
//        Test01 [] test01s = {
//                new Test01(22),
//                new Test01(122),
//                new Test01(21),
//                new Test01(2222),
//        };
//
//        // 创建策略
//        TestStrategy01 testStrategy01 = new TestStrategy01();
//        // 创建排序
//        TestSort01<Test01> testSort01 = new TestSort01();
//        /*testSort01.sort(test01s, (Test01 o1, Test01 o2) -> {
//            if(o1.width > o2.width){
//                return -1;
//            }else if(o1.width<o2.width){
//                return 1;
//            }else{
//                return 0;
//            }
//        });*/
//        testSort01.sort(test01s, testStrategy01);
//
//        for(Test01 item:test01s){
//            System.out.println(item.width);
//        }

        // 重新梳理 策略模式
        // 同种类型和另一类类型对比 没有掺杂策略
        /*Animal [] Cats = {
                new CatNotStrategy(32,24),
                new CatNotStrategy(12,44),
                new CatNotStrategy(121,414),
                new CatNotStrategy(0,0),
        };

        // 排序
        AnimalSortNotStrategy animalSortNotStrategy = new AnimalSortNotStrategy();
        animalSortNotStrategy.sort(Cats); // 只能对 CatNotStrategy 内部的排序属性所排序 如果要增加别的属性排序需要扩展类的方法并且修改sort的排序。或者把原来的擦了从写。

        for (Animal Cat:Cats){
            System.out.println(Cat);
        }*/

        // 增强带策略的写法
//        Animal [] CatList = {new Cat(3,4),
//          new Cat(11,21),
//          new Cat(13,41),
//          new Cat(0,0),
//        };
//
//        // 创建Cat的策略
//        CatStrategyWidth catStrategyWidth = new CatStrategyWidth();
//        // 创建排序 width
//        AnimalSort<Animal> animalSort = new AnimalSort<Animal>();
//        animalSort.sort(CatList, catStrategyWidth);
//        // 排序 height
//        animalSort.sort(CatList, (o1, o2) -> { // lamda 这里的形参类型可以不写自动推断。
//            if(o1.height < o2.height){
//                return -1;
//            }else if(o1.height > o2.height){
//                return 1;
//            }else {
//                return 0;
//            }
//        });
//
//
//        for (Animal cat: CatList){
//            System.out.println(cat);
//        }

        // 接口定义默认方法可以直接用
//        FunctionInterfaceClass functionInterfaceClass = new FunctionInterfaceClass();
//        functionInterfaceClass.m(); // 这个是接口里面的方法

        // 如何读取配置文件?
//        String f = "./src/main/resources/param.properties";
//        Properties props = new Properties();
//        try{
//            props.load(new java.io.FileInputStream(f));
//            String filepath = props.getProperty("test");
//            // 把class load 到内存 实例化
////            System.out.println(Class.forName(filepath).getDeclaredConstructors()[0].newInstance());
//            // 简单解释就是把单例子能到内存执行获取实力 作为上下文 给到下一个方法执行 建议熟读反射
//            Class.forName(filepath).getMethod("say").invoke(Class.forName(filepath).getMethod("getInstance").invoke(null));
//        }catch (Exception e){
//            e.printStackTrace();
//
//        SimpleIfc simple = SimpleFactory.getSimple();
//        simple.say();

//        // 抽象工厂
//        // 场景 一个司机 开着车 手拿武器 吃着面包
//        // 非工厂
//        Car car = new Car();
//        car.go();
//        Bread bread = new Bread();
//        bread.name();
//        Arms arms = new Arms();
//        arms.fire();
//        // 假如有个魔法世界的人它的坐骑 吃的 武器都不同
//        // 这个时候需要一个抽象工厂 抽象方法 不同的种族放不同的实例。
//        Broom broom = new Broom();
//        broom.go();
//        Mushroom mushroom = new Mushroom();
//        mushroom.name();
//        MagicWand magicWand = new MagicWand();
//        magicWand.fire();
//
//
//        // 详细解释产品族
//        /**
//         *
//         * 抽象出产品整个族的一系列需要的方法
//         * 例如 精灵 人
//         * 我需要调用族的 一系列的对象 但是不关心那个种族的物种 你传什么我用什么 注意工厂只生产对象 集合是抽象  里面的子对象也是抽象
//         */
//        // 通过工厂创建两种种族  通过抽象工厂解耦  抽象工厂生产抽象产品
//        SpeciesFactory p = new Spirit();
//        p.createA().fire();
//        p.createFood().name();
//        p.createTool().go();

        // 责任链
        // Chain of Responsibility
//        Chain chain = new Chain();
//        // register lambada
//        chain.setList((str, chainList)->{
//            System.out.println("startinga");
//            if(chainList.isHasNext()){
//                chainList.getList().format(str, chainList);
//            }
//            System.out.println(str + "-enda");
//            return true;
//        }).setList((str, chainList)->{
//            System.out.println("startingb");
//            if(chainList.isHasNext()){
//                chainList.getList().format(str, chainList);
//            }
//            System.out.println(str + "-endb");
//            return true;
//        }).setList((str, chainList)->{
//            System.out.println("startingc");
//            if(chainList.isHasNext()){
//                chainList.getList().format(str, chainList);
//            }
//            System.out.println(str + "-endc");
//            return true;
//        }).setList((str, chainList)->{
//            System.out.println("startingd");
//            if(chainList.isHasNext()){
//                chainList.getList().format(str, chainList);
//            }
//            System.out.println(str + "-endd");
//            return true;
//        });
//
//        chain.getList().format("admin", chain);

        // java 的链接口 java.servlet Filter FilterChain
//        ChainExt chainExt = new ChainExt();
//        ChainExt chainExt2 = new ChainExt();
//        Msg msg = new Msg();
//        msg.setMessage("admin");
//        chainExt2.add((m, chain)->{
//            System.out.println("atesta");
//            chain.getChain().doFilter(m,chain);
//            m.setMessage("aa");
//            System.out.println(m.getMessage());
//            return true;
//        }).add((m, chain)->{
//            System.out.println("btestb");
//            chain.getChain().doFilter(m,chain);
//            m.setMessage("bb");
//            System.out.println(m.getMessage());
//            return true;
//        }).add((m, chain)->{
//
//            System.out.println("ctestc");
//            chain.getChain().doFilter(m,chain);
//            m.setMessage("cc");
//            System.out.println(m.getMessage());
//            return true;
//        });
//
//        chainExt.add((m, chain)->{
//            System.out.println("testa");
//            chain.getChain().doFilter(m,chain);
//            m.setMessage("a");
//            System.out.println(m.getMessage());
//            return true;
//        }).add((m, chain)->{
//            System.out.println("testb");
//            chain.getChain().doFilter(m,chain);
//            m.setMessage("b");
//            System.out.println(m.getMessage());
//            return true;
//        }).add((m, chain)->{
//            System.out.println("testc");
//
//            ChainList c = chain.getChain();
//            c.doFilter(m, c);
//
//            m.setMessage("c");
//            System.out.println(m.getMessage());
//            return true;
//        }).add(chainExt2).doFilter(msg, chainExt);

        // 观察者 事件处理模型 observer 经常配合责任链使用 【观察者】是等待被调用方  【被观察者】调用观察者   接口call 代表被观察者要处理了要操作的事情   这里小孩醒了 观察者处理小孩醒了这个事情。call
        // Events 根据事件传递给观察者 观察者根据不同的事件做不同处理
        // 责任链可以中断 观察者一般不可以
        // 被观察者
        Child child = new Child();
        // 观察者
        Fahter fahter = new Fahter();
        Mom mom = new Mom();
        // 注册到被观察者中
        child.registerObserver(fahter).registerObserver(mom).registerObserver((e)->{ // Java 无法使用泛型lambda的的函数
            Child child1 = (Child) e.getSource();
            System.out.println(child1.isCry());
            System.out.println(e.getSource().getClass().getName());
        }).registerObserver(new Observer<Child>() {
            @Override
            public void call(Events<Child> events) {
                System.out.println(events.getSource().isCry());
            }
        });

        // 模拟小孩哭了
        child.wakeup();


    }
}
